package com.randb.easyhttp.request;

import com.google.gson.reflect.TypeToken;
import com.randb.easyhttp.cache.model.CacheResult;
import com.randb.easyhttp.callback.Callback;
import com.randb.easyhttp.callback.CallbackProxy;
import com.randb.easyhttp.func.ApiResultFunc;
import com.randb.easyhttp.func.CacheResultFunc;
import com.randb.easyhttp.func.HandleFunc;
import com.randb.easyhttp.func.RetryExceptionFunc;
import com.randb.easyhttp.model.ApiResult;
import com.randb.easyhttp.subscriber.CallbackSubscriber;
import com.randb.easyhttp.transformer.HandleErrorTransformer;
import com.randb.easyhttp.utils.RxUtils;
import com.randb.easyhttp.utils.Utils;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import okhttp3.ResponseBody;

/**
 * User: RandBII
 * Date: 2020/6/1
 * Description:
 */
@SuppressWarnings("unchecked")
public class CustomRequest extends BaseRequest<CustomRequest> {


    public CustomRequest() {
        super("");
    }

    public <T> T create(final Class<T> service) {
        checkValidate();
        return retrofit.create(service);
    }

    private void checkValidate() {
        Utils.checkNotNull(retrofit, "请先调用Build(), 才可使用");
    }

    @Override
    protected Observable<ResponseBody> generateRequest() {
        return null;
    }

    public <T> Observable<T> call(Observable<T> observable) {
        checkValidate();
        return observable.compose(RxUtils.io_main())
                .compose(new HandleErrorTransformer())
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay));
    }


    public <T> void call(Observable<T> observable, Callback<T> callback) {
        call(observable, new CallbackSubscriber(context, callback));
    }

    public <R> void call(Observable observable, Observer<R> subscriber) {
        observable.compose(RxUtils.io_main())
                .subscribe(subscriber);
    }

    public <T> Observable<T> apiCall(Observable<ApiResult<T>> observable) {
        checkValidate();
        return observable.map(new HandleFunc<T>())
                .compose(RxUtils.<T>io_main())
                .compose(new HandleErrorTransformer<T>())
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay));

    }

    public <T> Disposable apiCall(Observable<T> observable, Callback<T> callback) {
        return call(observable, new CallbackProxy<ApiResult<T>, T>(callback) {
        });
    }

    private <T> Disposable call(Observable<T> observable,
                                CallbackProxy<ApiResult<T>, T> callbackProxy) {
        Observable<CacheResult<T>> cacheObservable = build().toObservable(observable, callbackProxy);

        if (CacheResult.class != callbackProxy.getCallback().getRawType()) {
            return cacheObservable.compose(new ObservableTransformer<CacheResult<T>, T>() {
                @Override
                public ObservableSource<T> apply(Observable<CacheResult<T>> upstream) {
                    return upstream.map(new CacheResultFunc<T>());
                }
            }).subscribeWith(new CallbackSubscriber<T>(context, callbackProxy.getCallback()));

        } else {
            return cacheObservable.subscribeWith(new CallbackSubscriber<CacheResult<T>>(context,
                    callbackProxy.getCallback()));
        }


    }


    private <T> Observable<CacheResult<T>> toObservable(Observable<T> observable,
                                                        CallbackProxy<ApiResult<T>, T> callbackProxy) {
        return observable.map(new ApiResultFunc(callbackProxy != null
                ? callbackProxy.getType() : new TypeToken<ResponseBody>() {
        }.getType()))
                .compose(isSyncRequest ? RxUtils._main() : RxUtils._io_main())
                .compose(rxCache.transformer(cacheMode, callbackProxy.getCallback().getType()))
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay));
    }


}
